# -*- coding: utf-8 -*-
import time

import mod.server.extraServerApi as serverApi
from mod.server.system.serverSystem import ServerSystem

from dwjjCoreServerScripts.common import logger


class EntityModule(object):
    disableSpawnInWorldDict = dict()
    entityNearbyLimitCallLater = None
    entityNearbyLimitDisableWorlds = set()
    entityNearbyLimitIgnoreType = set()

    def __init__(self, serverSystem, config):
        # type: (ServerSystem, dict) -> None
        self.serverSystem = serverSystem
        self.config = config
        # 判断该系统是否启用
        if not config["enable"]:
            self.enable = False
            return
        # 初始化引擎工厂
        self.InitComp()
        # 初始化基础参数
        self.InitSetting()
        # 注册监听器
        self.InitListener()

    def InitComp(self):
        self.gameComp = serverApi.GetEngineCompFactory().CreateGame(serverApi.GetLevelId())

    def InitSetting(self):
        # 初始化 某些生物在某些世界禁止生成
        for k, v in self.config["disableSpawnInWorld"].items():
            dimId = int(k)
            entitySet = set()
            for v2 in v:
                entitySet.add(v2.encode("utf-8"))
            self.disableSpawnInWorldDict[dimId] = entitySet

        # 初始化 实体密集检测
        entityNearbyLimitDict = self.config["entityNearbyLimit"]
        if entityNearbyLimitDict["enable"]:
            # 初始化关闭的世界
            for d in entityNearbyLimitDict["disableWorlds"]:
                self.entityNearbyLimitDisableWorlds.add(int(d))
            # 忽略的类型
            for t in entityNearbyLimitDict["check"]["ignoreType"]:
                self.entityNearbyLimitIgnoreType.add(t.encode("utf-8"))
            # 创建计时器
            self.entityNearbyLimitCallLater = self.gameComp.AddRepeatedTimer(
                entityNearbyLimitDict["interval"], self.ExecutorEntityNearbyLimit,
                entityNearbyLimitDict=entityNearbyLimitDict
            )

    def InitListener(self):
        self.serverSystem.ListenForEvent(serverApi.GetEngineNamespace(), serverApi.GetEngineSystemName(),
                                         "ServerSpawnMobEvent", self, self.OnSpawnEntity, 10)

    def ExecutorEntityNearbyLimit(self, entityNearbyLimitDict):
        startTime = time.time()
        checkRange = entityNearbyLimitDict["range"]
        limitAmount = entityNearbyLimitDict["amount"]
        checkDict = entityNearbyLimitDict["check"]
        entityTypeEnum = serverApi.GetMinecraftEnum().EntityType



        # 开始遍历全局生物
        entitySum = 0
        destroyEntitySet = set()
        for entityId, entityDict in serverApi.GetEngineActor().items():
            entitySum = entitySum + 1
            if entityDict["dimensionId"] not in self.entityNearbyLimitDisableWorlds:
                isCheck = False
                entityComp = serverApi.GetEngineCompFactory().CreateEngineType(entityId)
                entityType = entityComp.GetEngineType()

                # 判断忽略类型
                if entityComp.GetEngineTypeStr() in self.entityNearbyLimitIgnoreType:
                    continue
                # 判断是否带名字
                if checkDict["ignoreHasName"] and (serverApi.GetEngineCompFactory().CreateName(entityId).GetName() is not None):
                    continue
                # 判断条件 动物 怪物 环境生物 水生物 村民
                if (entityType & entityTypeEnum.Animal == entityTypeEnum.Animal) and checkDict["animals"] or \
                   (entityType & entityTypeEnum.Monster == entityTypeEnum.Monster) and checkDict["monster"] or \
                   (entityType & entityTypeEnum.Ambient == entityTypeEnum.Ambient) and checkDict["ambient"] or \
                   (entityType & entityTypeEnum.WaterAnimal == entityTypeEnum.WaterAnimal) and checkDict["waterAnimal"] or \
                   (entityType & entityTypeEnum.VillagerBase == entityTypeEnum.VillagerBase) and checkDict["villagerBase"]:
                    isCheck = True
                # 开始检测周围生物
                if isCheck:
                    nearbyList = self.gameComp.GetEntitiesAroundByType(entityId, checkRange, entityType)
                    if len(nearbyList) > limitAmount:
                        destroyEntitySet.add(entityId)

        for entityId in destroyEntitySet:
            self.serverSystem.DestroyEntity(entityId)

        # debug信息
        endTime = time.time()
        resultTime = ("%.4f" % (endTime - startTime))
        logger.Debug("本次实体密集检测总计耗时 " + str(resultTime) + " 秒, 全服共有 " + str(entitySum) + " 个实体, 本次删除 " + str(len(destroyEntitySet)) + " 个")

    def OnSpawnEntity(self, e):
        entityIdentifier = e["identifier"]
        spawnDim = e["dimensionId"]

        if spawnDim in self.disableSpawnInWorldDict:
            if entityIdentifier in self.disableSpawnInWorldDict[spawnDim]:
                e["cancel"] = True


